var GenericMainWindow = GFMainWindow.extend({
	obj_id: null,
	constructor: function(id,selchg_handler,fixed)
	{
		var html;
		var x = this;

		html = '<ul>';
		html += lib.sprintf('<li style="font-size: small;">GownFull</li>',id);
		html += lib.sprintf('<li><select id="%s_Select"><option class="%s" value="0">Disabled</option></select></li>',id,GownFullConfig.disable_input_method_class_name);
		html += lib.sprintf('<li id="%s_Extension">&nbsp;</li>',id);
		html += lib.sprintf('<li><span id="%s_Preedit" class="%s">&nbsp;</span></li>',id,GownFullConfig.preedit_class_name);
		html += '</ul>';

		this.obj_id = id;
		if(fixed) this.base(new GFWindowFixedBehavior(id,GownFullConfig.mainwin_class_name),html,selchg_handler);
		else this.base(new GFWindowMovableBehavior(id,0,0,null,null,GownFullConfig.mainwin_class_name),html,selchg_handler);

		var sel = this.GetSelect();
		if(sel) {
			if(GownFullBrowserDetect.use_addEventListener) 
				sel.addEventListener('change',function() { return x.onSelectChange(this); },false);
			else 
				sel.onchange = function() { return x.onSelectChange(this); };
		}
	},
	CreateExtensionDIV: function(id,class_name,width,height,content)
	{
		var node;
		var ext;

		ext = document.getElementById(lib.sprintf('%s_Extension',this.obj_id));
		if(!ext) return null;

		node = document.createElement('span');
		if(class_name) node.className = class_name;
		if(width) node.style.width = lib.sprintf('%dpx',width);
		if(height) node.style.height = lib.sprintf('%dpx',height);
		node.innerHTML = content;
		ext.appendChild(node);
		Debug.trace(0,"GenericGownFullBuilder: Create an extension DIV with id=\"%s\"",id);
		return node;
	},
	DestroyExtensionDIV: function(id)
	{
		var node;
		var ext;

		ext = document.getElementById(lib.sprintf('%s_Extension',this.obj_id));
		if(!ext) return false;

		node = document.getElementById(id);
		if(!node) return false;

		ext.removeChild(node);
		Debug.trace(0,"GenericGownFullBuilder: Destroy extension DIV id=\"%s\"",id);
		return true;
	},
	GetSelect: function()
	{
		var buf;
		
		buf = document.getElementById(this.obj_id + '_Select');
		if(buf) return buf;
		else return null;
	},
	AddSelectOption: function(text,value,type)
	{
		var sel = this.GetSelect();
		var opt = document.createElement('option');
		opt.value = value;
		switch(type) {
		case this.TYPE_AVAILABLE: opt.className = GownFullConfig.available_input_method_class_name; break;
		case this.TYPE_DOWNLOAD: opt.className = GownFullConfig.download_input_method_class_name; break;
		default: opt.className = GownFullConfig.disable_input_method_class_name; break;
		}
		opt.appendChild(document.createTextNode(text));
		sel.appendChild(opt);
		return opt;
	},
	ReplaceSelectOption: function(old_value,text,value,type)
	{
		var sel = this.GetSelect();
		// find option object with value == old
		var i,opt;
		var e = sel.childNodes;
		
		opt = null;
		for(i=0;i<e.length;i++) {
			obj = e[i];
			if(obj.value && obj.value == old_value) opt = obj;
		}
		if(!opt) return false;

		var newopt = document.createElement('option');
		newopt.value = value;
		switch(type) {
		case this.TYPE_AVAILABLE: opt.className = GownFullConfig.available_input_method_class_name; break;
		case this.TYPE_DOWNLOAD: opt.className = GownFullConfig.download_input_method_class_name; break;
		default: opt.className = GownFullConfig.disable_input_method_class_name; break;
		}
		newopt.appendChild(document.createTextNode(text));
		sel.replaceChild(newopt,opt);
		return newopt;
	},
	SelectOption: function(value)
	{
		var sel = this.GetSelect();
		var opt;
		// select the new opt
		for(i=0;i<sel.options.length;i++) {
			opt = sel.options[i];
			if(opt && opt.value == value) {
				sel.selectedIndex = i;
				this.selchg_handler(opt.value);
				break;
			}
		}
	},
	GetPreedit: function()
	{
		var buf;
		
		buf = document.getElementById(this.obj_id + '_Preedit');
		if(buf) return buf;
		else return null;
	},
	SetPreedit: function(str)
	{
		var buf;
		
		buf = document.getElementById(this.obj_id + '_Preedit');
//		if(buf && buf.firstChild) buf.firstChild.nodeValue = str;
		buf.innerHTML = str;
	},
	ResetPreedit: function()
	{
		var buf;

		buf = this.GetPreedit();
		if(buf) {
			if(buf.className) buf.className = GownFullConfig.preedit_class_name;
//			if(buf.firstChild) buf.firstChild.nodeValue = '';
			buf.innerHTML = '';
		}
	},
	SetPreeditText: function(str)
	{
		var buf;

		buf = this.GetPreedit();
		if(buf) {
			if(buf.className) buf.className = GownFullConfig.preedit_status_class_name;
			//if(buf.firstChild) buf.firstChild.nodeValue = str;
			buf.innerHTML = str;
		}
	},
	DeletePreedit: function(c)
	{
		var buf;

		if(c == null) c = 1;

		buf = this.GetPreedit();
		if(buf) {
			if(buf.className && buf.className != GownFullConfig.preedit_class_name) this.ResetPreedit();
			var str = buf.innerHTML;
			str = str.substr(0,str.length - c);
			buf.innerHTML = str;
/*			if(buf.firstChild) {
				var str = buf.firstChild.nodeValue;
				str = str.substr(0,str.length - c);
				buf.firstChild.nodeValue = str;
			}
*/
		}
	},
	AppendPreedit: function(c)
	{
		var buf;

		buf = this.GetPreedit();
		if(buf) {
			if(buf.className) {
				if(buf.className != GownFullConfig.preedit_class_name) {
					 //if(buf.firstChild) buf.firstChild.nodeValue = '';
					buf.innerHTML = '';
				}
				buf.className = GownFullConfig.preedit_class_name;
			}
			buf.innerHTML += c;
//			if(buf.firstChild) buf.firstChild.nodeValue += c;
		}
	},
	SetPreeditInvalid: function()
	{
		var buf;

		buf = this.GetPreedit();
		if(buf) buf.className = GownFullConfig.preedit_invalid_class_name;
	},
	onSelectChange: function(sel)
	{
		this.selchg_handler(sel.value);
	}
});

var GenericCandidateListWindow = GFCandidateListWindow.extend({
	obj_id: null,
	constructor: function(id,fixed)
	{
		var html = '<span>Candidates</span>';
		html += '<ol>';

		for(i=1;i<=9;i++) {
			html += lib.sprintf('<li id="%s_Candidate%d">&nbsp;</li>',id,i);
		}
		html += '</ol>';

		this.obj_id = id;
		if(fixed) this.base(new GFWindowFixedBehavior(id,GownFullConfig.candwin_class_name),html);
		else this.base(new GFWindowMovableBehavior(id,Math.round(GFWindowsMovableHandler.GetClientWidth()/3),0,128,null,GownFullConfig.candwin_class_name),html);
	},
	GetCandidateObject: function(i)
	{
		return document.getElementById(lib.sprintf("%s_Candidate%d",this.obj_id,i));
	},
	SetCandidate: function(i,str)
	{
		var obj,text;

		obj = this.GetCandidateObject(i);
		if(!obj) return false;
		if(!obj.firstChild) return false;
		text = obj.firstChild;
		text.nodeValue = str;
		return true;
	}
});

var GenericGownFullObjectHandler = GownFullObjectHandler.extend({
	constructor: function()
	{
	},
	sendstr_nodeName_handler: {
		'input': function(o,s) 
		{
			if(o.type && o.type == 'text') {
				if(o.focus) o.focus();
				if(o.selectionStart != null) {
					var last_scrollleft = o.scrollLeft;
					var last_scrolltop = o.scrollTop;
					var start = o.selectionStart;
					var end = o.selectionEnd;
					var len = o.value.length;
	
					o.value = o.value.substring(0,start) + s + o.value.substring(end,len);
					start = start + s.length;
					end = start;
					if(o.setSelectionRange) o.setSelectionRange(start,end);
					else {
						o.selectionStart = start;
						o.selectionEnd = end;
					}
					o.scrollLeft = last_scrollleft;
					o.scrollTop = last_scrolltop;
				}
				else if(document.selection) {
					var sel = document.selection.createRange();
					sel.text = s;
					sel.collapse(false);
					sel.select();
				}
				else o.value += s;
			}
			else return false;
		},
		'textarea': function(o,s) 
		{
			if(o.focus) o.focus();
			if(o.selectionStart != null) {
				var last_scrollleft = o.scrollLeft;
				var last_scrolltop = o.scrollTop;
				var start = o.selectionStart;
				var end = o.selectionEnd;
				var len = o.value.length;

				o.value = o.value.substring(0,start) + s + o.value.substring(end,len);
				start = start + s.length;
				end = start;
				if(o.setSelectionRange) o.setSelectionRange(start,end);
				else {
					o.selectionStart = start;
					o.selectionEnd = end;
				}
				o.scrollLeft = last_scrollleft;
				o.scrollTop = last_scrolltop;
			}
			else if(document.selection) {
				var sel = document.selection.createRange();
				sel.text = s;
				sel.collapse(false);
				sel.select();
			}
			else o.value += s;
		},
		'html': function(o,s)  // iframe
		{
			var win;

			if(!o.GownFull_iframe) {
				Debug.trace(0,'GenericGownFullObjectHandler: (iframe) handler cannot get iframe reference.');
				return;
			}
			o = o.GownFull_iframe;

			if(o.contentWindow) win = o.contentWindow;
			else if(o.window) win = o.window;
			else {
				Debug.trace(0,'GenericGownFullObjectHandler: (iframe) handler cannot get content window.');
				return;
			}
			var sel = win.getSelection();
			var range;
			var d;
		
			if(!sel.isCollapsed) sel.deleteFromDocument();
			d = document.createElement('div');
			d.innerHTML = s;
			range = sel.getRangeAt(sel.rangeCount-1);
			for(i=d.childNodes.length-1;i>=0;i--) {
				range.insertNode(d.childNodes[i]);
			}
			sel.collapseToEnd();
		}
	}
});

var GenericGownFullBuilder = GownFullBuilder.extend({
	show: true,
	last_im: 0,
	config: null,

	constructor: function(config)
	{
		this.config = {};
		this.config.mainwin_id = GownFullConfig.mainwin_id;
		this.config.candwin_id = GownFullConfig.candwin_id;
		this.config.css_file = GownFullConfig.css_file;
		this.config.fixed = false;
		this.config.applyall = true;

		if(config) {
			for(var key in config) this.config[key] = config[key];
		}
		Debug.trace(0,'GownFullBuilder: Using GenericGownFullBuilder (fixed=%s).',this.config.fixed);
		this.base();
	},
	BuildObjectHandler: function()
	{
		return new GenericGownFullObjectHandler;
	},
	BuildCSS: function()
	{
		return lib.LoadCSSFile(this.config.css_file);
	},
	BuildMainWindow: function(selchg)
	{
		if(this.config.fixed) return new GenericMainWindow(this.config.mainwin_id,selchg,true);
		else return new GenericMainWindow(this.config.mainwin_id,selchg);
	},
	BuildCandidateListWindow: function()
	{
		if(this.config.fixed) return new GenericCandidateListWindow(this.config.candwin_id,true);
		else return new GenericCandidateListWindow(this.config.candwin_id);
	},
	onKeyDown: function(e)
	{
		var key = e.which ? e.which : e.keyCode;
		var obj = lib.GetEventTarget(e);
		var b;

		b = this.keydown_handler(obj,key);
		
		if(!b) {
			if(e.preventDefault) e.preventDefault();
		}
		return b;
	},
	onKeyUp: function(e)
	{
		var key = e.which ? e.which : e.keyCode;
		var obj = lib.GetEventTarget(e);
		var b;

		b = this.keyup_handler(obj,key);

		if(!b) {
			if(e.preventDefault) e.preventDefault();
		}
		return b;
	},
	onKeyPress: function(e)
	{
		var key = e.which ? e.which : e.keyCode;
		var obj = lib.GetEventTarget(e);
		var b;

		b = this.keypress_handler(obj,key);

		if(!b) {
			if(e.preventDefault) e.preventDefault();
		}
		return b;
	},
	AttachHandler: function(obj)
	{
		var x = this;

		if(obj.nodeName && obj.nodeName.toLowerCase() == 'iframe') {
			var doc;

			if(obj.document) doc = obj.document;
			else if(obj.contentDocument) doc = obj.contentDocument;

			if(doc.documentElement) doc.documentElement.GownFull_iframe = obj;
			obj = doc;
		}

		if(GownFullBrowserDetect.use_key_addEventListener) {
			obj.addEventListener("keydown", function(e) { return x.onKeyDown(e); },true);
			obj.addEventListener("keypress", function(e) { return x.onKeyPress(e); },true);
			obj.addEventListener("keyup", function(e) { return x.onKeyUp(e); },true);
		}
		else {
			obj.onkeydown = function() { return x.onKeyDown(window.event); }
			obj.onkeypress = function() { return x.onKeyPress(window.event); }
			obj.onkeyup = function() { return x.onKeyUp(window.event); }
		}
		return true;
	},
	ApplyInputMethodByTagName: function(name,filter)
	{
		var nodes,c,i;

		nodes = document.getElementsByTagName(name);
		c = 0;
		for(i=0;i<nodes.length;i++) {
			if(!filter || filter(nodes.item(i))) {
				if(this.AttachHandler(nodes.item(i))) c++;
			}
		}
		Debug.trace(0,"GenericGownFullBuilder: Input Method attached for HTML tag %s, %d attached.",name,c);
		return c;
	},
	PostCreateGownFull: function()
	{
		if(this.config.applyall) {
			this.ApplyInputMethodByTagName('input',function(obj) { return (obj.type && obj.type == 'text') ? true : false; });
			this.ApplyInputMethodByTagName('textarea');
/*
			this.ApplyInputMethodByTagName('iframe', function(obj) {
				var doc;

				if(obj.contentDocument) doc = obj.contentDocument;
				else if(obj.document) doc = obj.document;
				else return false;

				if(doc.designMode && doc.designMode == 'on') return true;
				else return false;
			});
*/
		}
	}
});
